home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / timer / sun3.md / timerIntersil.c < prev    next >
C/C++ Source or Header  |  1990-11-08  |  20KB  |  783 lines

  1. /*
  2.  * timerIntersil.c --
  3.  *
  4.  *    This file contains routines that manipulate the Intersil
  5.  *    ICM7170 real-time clock chip for the SUN-3.
  6.  *    (For a detailed explanation of the chip, see the data sheet
  7.  *    for the ICM7170 [Dec. 1985, 301680-005].)
  8.  *
  9.  *    The Intersil chip is used to provide perdiodic interrupts
  10.  *    and contains a set of free-running counters that keep track of time.
  11.  *    The routine in this file are used to setup the chip to
  12.  *    cause interrupts every 10 milliseconds (100th of second)
  13.  *    and maintain the time since the counters were initialized.
  14.  *
  15.  *      According to the Sun-3 Architecture manual (rev. 2.0, 25 July
  16.  *      1985), The chip's "interrupt output signal causes an interrupt
  17.  *      request on level 5 or 7 via the interrupt register." The routines
  18.  *      in this file set and reset the level-5 interrupt enable bit in the
  19.  *      interrupt register.  It also assumed that level-7 interrupts are
  20.  *      disabled.
  21.  *
  22.  *    The AMD timer chip on the Sun-2 provides several timers and
  23.  *    two of them are used by the Timer_ module for controlling the 
  24.  *    callback queue and profiling. Unfortunately the Intersil chip 
  25.  *    provides just one timer. The two timers used by the Timer module
  26.  *    are built from the chip's single timer. Thus whenever the
  27.  *    Intersil chip's timer interrupts, the two virtual timers
  28.  *    can appear to have gone off. Unlike the timers on the Sun-2,
  29.  *    the virtual timers can not cause indepdent interrupts.
  30.  *
  31.  *    The free-running counters on the Intersil chip can be used to
  32.  *    keep the time of day in Unix format (i.e. the time since 1/1/1970).
  33.  *    The counter is used here to keep track of the amount of time
  34.  *    since the system was booted.
  35.  *
  36.  *    Additional Timer_Counter routines are provided to convert from/to
  37.  *    32-bit interval values (described in timerClock.c) to/from time.
  38.  *    The interval represents an machine-dependent format for small 
  39.  *    time values. For the Sun-3, an interval is a fraction of second
  40.  *    because it is easily converted to the units that the free-running 
  41.  *    counters count in.
  42.  *
  43.  * Copyright 1986 Regents of the University of California
  44.  * All rights reserved.
  45.  */
  46.  
  47.  
  48. #ifndef lint
  49. static char rcsid[] = "$Header: /sprite/src/kernel/timer/sun3.md/RCS/timerIntersil.c,v 9.3 90/10/19 15:59:00 rab Exp $ SPRITE (Berkeley)";
  50. #endif /* not lint */
  51.  
  52. #include <sprite.h>
  53. #include <sys.h>
  54. #include <mach.h>
  55. #include <machConst.h>
  56. #include <devAddrs.h>
  57. #include <timer.h>
  58. #include <timerInt.h>
  59. #include <timerIntersilInt.h>
  60. #include <spriteTime.h>
  61. #include <stdio.h>
  62. #include <assert.h>
  63.  
  64. /* For profiling call */
  65. #include "prof.h"
  66. /* For CallBack call */
  67. #include "timer.h"
  68.  
  69. static volatile TimerDevice *timerRegsPtr = 
  70.     (volatile TimerDevice *) DEV_TIMER_ADDR;
  71.  
  72. /*
  73.  * Flags to indicate whether a timer is enabled or not.
  74.  */
  75. static Boolean profileIntrsWanted = FALSE;
  76. static Boolean callbackIntrsWanted = FALSE;
  77.  
  78. /*
  79.  * Initial state of the timer's interrupt enable/disable bit.
  80.  */
  81.  
  82. static int timerIntrState = INTR_DISABLE;
  83. static int timerActive = FALSE;
  84.  
  85. /*
  86.  * Frequency of the timer's interrupts.
  87.  */
  88. #define TIMER_INTR_FREQ     S100TH_SEC_MASK
  89.  
  90. /*
  91.  * Initial values of the free-running counters.
  92.  * According to the Intersil data sheet, the month and day
  93.  * counters start counting at 1.
  94.  */
  95. static    IntersilCounters    initialCounter = {
  96.     0,    /* hundredths */
  97.     0,    /* hours */
  98.     0,    /* minutes */
  99.     0,    /* seconds */
  100.     1,    /* month */
  101.     1,    /* day */
  102.     0,    /* year */
  103.     0,    /* dayOfWeek */
  104. };
  105.  
  106.  
  107. /*
  108.  * Routine to calculate a time value from the values in the free-running
  109.  * counters.
  110.  */
  111.  
  112. static void CountersToTime();
  113. int Timer_TimerServiceInterrupt();
  114.  
  115.  
  116.  
  117. /*
  118.  * Timer interval expressed as an integer and as a Time. This is the
  119.  * period between callbacks, so it is actually twice the timer period
  120.  * since we callback every other time. A tick on a sun3 is 1 ms and
  121.  * we callback every 20 ms.
  122.  */
  123.  
  124. static unsigned int interval = TIMER_CALLBACK_INTERVAL_APPROX / 1000;
  125. static Time time = { 0, TIMER_CALLBACK_INTERVAL_APPROX};
  126. /*
  127.  * Constants used to convert the contents of the free-running counters
  128.  * to time in seconds and microseconds.
  129.  */
  130.  
  131. #define SECS_PER_MIN    60
  132. #define SECS_PER_HOUR    SECS_PER_MIN * 60
  133. #define SECS_PER_DAY     SECS_PER_HOUR * 24
  134. #define SECS_PER_YEAR    SECS_PER_DAY * 365
  135.  
  136. /*
  137.  * Number of seconds since the beginning of the year to the
  138.  * beginning of a month.
  139.  */
  140. static int accumSecsPerMonth[13] = {
  141.     0,        /* nothing */
  142.     0 * SECS_PER_DAY,        /* Jan */
  143.     31 * SECS_PER_DAY,        /* Feb */
  144.     59 * SECS_PER_DAY,        /* Mar */
  145.     90 * SECS_PER_DAY,        /* Apr */
  146.     120 * SECS_PER_DAY,        /* May */
  147.     151 * SECS_PER_DAY,        /* Jun */
  148.     181 * SECS_PER_DAY,        /* Jul */
  149.     212 * SECS_PER_DAY,        /* Aug */
  150.     243 * SECS_PER_DAY,        /* Sep */
  151.     273 * SECS_PER_DAY,        /* Oct */
  152.     304 * SECS_PER_DAY,        /* Nov */
  153.     334 * SECS_PER_DAY,        /* Dec */
  154. };
  155.  
  156. /*
  157.  * Version of above for leap years.
  158.  */
  159. static int accumSecsPerMonthLeap[13] = {
  160.     0,        /* nothing */
  161.     0 * SECS_PER_DAY,        /* Jan */
  162.     31 * SECS_PER_DAY,        /* Feb */
  163.     60 * SECS_PER_DAY,        /* Mar */
  164.     91 * SECS_PER_DAY,        /* Apr */
  165.     121 * SECS_PER_DAY,        /* May */
  166.     152 * SECS_PER_DAY,        /* Jun */
  167.     182 * SECS_PER_DAY,        /* Jul */
  168.     213 * SECS_PER_DAY,        /* Aug */
  169.     244 * SECS_PER_DAY,        /* Sep */
  170.     274 * SECS_PER_DAY,        /* Oct */
  171.     305 * SECS_PER_DAY,        /* Nov */
  172.     335 * SECS_PER_DAY,        /* Dec */
  173. };
  174.  
  175.  
  176.  
  177.  
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * Timer_TimerInit --
  182.  *
  183.  *    Initialize the ICM7170 chip.
  184.  *
  185.  *    N.B. This routine must be called before Timer_TimerStart.
  186.  *
  187.  * Results:
  188.  *    None.
  189.  *
  190.  * Side effects:
  191.  *    The timer is initialized and ready to start ticking.
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195.  
  196. /*ARGSUSED*/
  197. void
  198. Timer_TimerInit(timer)
  199.     unsigned short     timer;        /* Ignored for Sun-3 version. */
  200. {
  201.     static Boolean init = FALSE;
  202.     unsigned char c;
  203.  
  204.     if (!init) {
  205.     init = TRUE;
  206.     /*
  207.      * Register our call back function.
  208.      */
  209.      Mach_SetHandler(29, Timer_TimerServiceInterrupt, (ClientData) 0); 
  210.     /*
  211.      * Tell the chip to prevent interrupts.
  212.      */
  213.     timerIntrState = INTR_DISABLE;
  214.     timerRegsPtr->commandReg = IntersilCommand(RUN, timerIntrState);
  215.  
  216.     /*
  217.      * Tell the chip to cause periodic interrupts.
  218.      */
  219.     timerRegsPtr->interruptReg = TIMER_INTR_FREQ;
  220.  
  221.     /*
  222.      * Read the chip's interrupt register to clear any pending inerrupts.
  223.      */
  224.     c = timerRegsPtr->interruptReg;
  225. #ifdef lint
  226.     c = c;
  227. #endif
  228.     }
  229. }
  230.  
  231.  
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * Timer_TimerStart --
  236.  *
  237.  *    Start the timer so it will cause periodic interrupts.
  238.  *    N.B. The timer must have been initialized with Timer_TimerInit
  239.  *    before this routine is called.
  240.  *
  241.  * Results:
  242.  *    None.
  243.  *
  244.  * Side effects:
  245.  *    The timer starts ticking.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249.  
  250. void
  251. Timer_TimerStart(timer)
  252.     unsigned short timer;
  253. {
  254.     if (timer == TIMER_CALLBACK_TIMER) {
  255.     callbackIntrsWanted = TRUE;
  256.     } else if (timer == TIMER_PROFILE_TIMER) {
  257.     profileIntrsWanted = TRUE;
  258.     } else {
  259.     panic("Timer_TimerStart: unknown timer %d\n", timer);
  260.     }
  261.     if (!timerActive) {
  262.     timerActive = TRUE;
  263.     /*
  264.      * Tell the chip to start counting and allow it to cause interrupts.
  265.      */
  266.     timerIntrState = INTR_ENABLE;
  267.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_ENABLE);
  268.     
  269.     /*
  270.      * Enable timer interrupts in the system's interrupt register.
  271.      */
  272.     
  273.     *Mach_InterruptReg |= MACH_ENABLE_LEVEL5_INTR;
  274.     }
  275. }
  276.  
  277.  
  278. /*
  279.  *----------------------------------------------------------------------
  280.  *
  281.  * Timer_TimerInactivate --
  282.  *
  283.  *    Stops the timer so that it will not cause interrupts.
  284.  *
  285.  * Results:
  286.  *    None.
  287.  *
  288.  * Side effects:
  289.  *    The timer is stopped.
  290.  *
  291.  *----------------------------------------------------------------------
  292.  */
  293.  
  294. void
  295. Timer_TimerInactivate(timer)
  296.     register unsigned short timer;
  297. {
  298.     if (timer == TIMER_CALLBACK_TIMER) {
  299.     callbackIntrsWanted = FALSE;
  300.     } else if (timer == TIMER_PROFILE_TIMER) {
  301.     profileIntrsWanted = FALSE;
  302.     } else {
  303.     panic("Timer_TimerInactivate: unknown timer %d\n", timer);
  304.     }
  305.  
  306.     /*
  307.      * If neither type of timer interrupt is wanted, then disable
  308.      * timer interrupts.
  309.      */
  310.  
  311.     if (!callbackIntrsWanted && !profileIntrsWanted) {
  312.     timerActive = FALSE;
  313.     *Mach_InterruptReg &= ~MACH_ENABLE_LEVEL5_INTR;
  314.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_DISABLE);
  315.     }
  316. }
  317.  
  318.  
  319. #if 0
  320. /*
  321.  *----------------------------------------------------------------------
  322.  *
  323.  * Timer_TimerGetStatus --
  324.  *
  325.  *    Clears the interrupt pending bit in the interrupt register
  326.  *    and reads the interrupt status register (ISR) of the chip.
  327.  *    The ISR must be read in order to reset the interrupt, according
  328.  *    to the Intersil data sheet (p.6, "Periodic Interrupts").
  329.  *    (It seems that the value is always 0.) According to the
  330.  *    Sun-3 architure manual (p.31), the level-5 bit in the interrupt 
  331.  *    register must be toggled to clear the interrupt.
  332.  *
  333.  * Results:
  334.  *    The value of the status register.
  335.  *
  336.  * Side effects:
  337.  *    The interrupt is cleared.
  338.  *
  339.  *----------------------------------------------------------------------
  340.  */
  341.  
  342. #ifndef lint
  343. static unsigned short
  344. Timer_TimerGetStatus()
  345. {
  346.     unsigned char statusReg;
  347.     unsigned char intrReg;
  348.  
  349.     intrReg = *Mach_InterruptReg & MACH_ENABLE_LEVEL7_INTR;
  350.  
  351.     *Mach_InterruptReg &= ~(MACH_ENABLE_LEVEL5_INTR | 
  352.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  353.  
  354.     statusReg = timerRegsPtr->interruptReg;
  355.  
  356.     *Mach_InterruptReg |= (MACH_ENABLE_LEVEL5_INTR | 
  357.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  358.  
  359.     /*
  360.      * Read the chip again in case an obscure race condition occurs.
  361.      * (This is how Sun handles it.)
  362.      */
  363.     statusReg = timerRegsPtr->interruptReg;
  364.  
  365.     return(statusReg);
  366. }
  367. #endif
  368.  
  369.  
  370. /*
  371.  *----------------------------------------------------------------------
  372.  *
  373.  * Timer_TimerExamineStatus --
  374.  *
  375.  *    Assuming the interrupt is valid, return TRUE or FALSE if 
  376.  *    the interrupt is or is not allowed for the specified timer.
  377.  *    (The status register is always 0 on the Sun-3 so we can't tell
  378.  *    if the chip really did interrupt.)
  379.  *
  380.  *    This routine is used to decrease the frequency of
  381.  *    a virtual timer. The callback timer's frequency is
  382.  *    one-half of the real timer's frequency.
  383.  *
  384.  * Results:
  385.  *    TRUE        if the timer interrupted.
  386.  *    FALSE        if the timer did not interrupt.
  387.  *
  388.  * Side effects:
  389.  *    The callback virtual timer's toggle is changed.
  390.  *
  391.  *----------------------------------------------------------------------
  392.  */
  393.  
  394. #ifndef lint
  395. /*ARGSUSED*/
  396. static Boolean
  397. Timer_TimerExamineStatus(statusReg, timer, spuriousPtr)
  398.     unsigned int statusReg;    /* Ignored because it is always 0. */
  399.     unsigned int timer;        /* Virtual Timer # */
  400.     Boolean *spuriousPtr;    /* Always set FALSE. */
  401. {
  402.     static Boolean callbackTimerToggle = FALSE;
  403.  
  404.     /*
  405.      * Assume we never get a spurious interrupt because the statusReg
  406.      * value is always 0 on the Sun-3. 
  407.      */
  408.     *spuriousPtr = FALSE;
  409.  
  410.     if (timer == TIMER_CALLBACK_TIMER) {
  411.     /*
  412.      * Cut the timer's frequency in half.
  413.      */
  414.     callbackTimerToggle = !callbackTimerToggle;
  415.     return(callbackTimerToggle);
  416.     } else if (timer == TIMER_PROFILE_TIMER) {
  417.     if (profileIntrsWanted) {
  418.         return(TRUE);
  419.     } else {
  420.         return(FALSE);
  421.     }
  422.     } else {
  423.     printf("Timer_TimerExamineStatus: unknown timer %d\n", 
  424.                 timer);
  425.     return(FALSE);
  426.     }
  427. }
  428. #endif
  429. #endif
  430.  
  431. /*
  432.  *----------------------------------------------------------------------
  433.  *
  434.  *  Timer_TimerServiceInterrupt --
  435.  *
  436.  *      This routine is called at every timer interrupt. 
  437.  *      It calls the timer callback queue handling if the callback timer 
  438.  *    expired and calls the profiling interrupt handling if the 
  439.  *    profile callback timer expired.
  440.  *
  441.  *  Results:
  442.  *    None.
  443.  *
  444.  *  Side Effects:
  445.  *    Routines on the timer queue may cause side effects. Profile
  446.  *    collect may take place. 
  447.  *    
  448.  *
  449.  *----------------------------------------------------------------------
  450.  */
  451.  
  452. /*ARGSUSED*/
  453. int
  454. Timer_TimerServiceInterrupt(clientData, stack)
  455.     ClientData        clientData;
  456.     Mach_IntrStack stack;
  457.     /*
  458.      *  Determine if the callback and profile timers have expired.
  459.      *  Timer_TimerExamineStatus has the side effect of clearing the timer's
  460.      *  "cause interrupt" bit if it was set. 
  461.      *
  462.      *  The profile timer is checked first because routines on the callback
  463.      *  queue might cause a delay in collecting profiling information.
  464.      */
  465.  
  466.     unsigned short timerStatus;
  467.     register unsigned char intrReg;
  468.     static Boolean callbackTimerToggle = FALSE;
  469.  
  470.     /*
  471.      * Begin in-lined Timer_TimerGetStatus().  This is done mostly
  472.      * to clear the interrupt as the status returned is always zero.
  473.      */
  474.     intrReg = *Mach_InterruptReg & MACH_ENABLE_LEVEL7_INTR;
  475.  
  476.     *Mach_InterruptReg &= ~(MACH_ENABLE_LEVEL5_INTR | 
  477.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  478.  
  479.     timerStatus = timerRegsPtr->interruptReg;
  480.  
  481.     *Mach_InterruptReg |= (MACH_ENABLE_LEVEL5_INTR | 
  482.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  483.  
  484.     /*
  485.      * Read the chip again in case an obscure race condition occurs.
  486.      * (This is how Sun handles it.)
  487.      */
  488.     timerStatus = timerRegsPtr->interruptReg;
  489. #ifdef lint
  490.     timerRegsPtr->interruptReg = timerStatus;
  491. #endif
  492.     /*
  493.      * End in-lined Timer_TimerGetStatus
  494.      */
  495.  
  496.     if (mach_KernelMode) {
  497.     /*
  498.      * Check for kernel profiling.  We'll sample the PC here.
  499.      */
  500.     assert((stack.excStack.statusReg & MACH_SR_SUPSTATE) != 0);
  501.     if (profileIntrsWanted) {
  502.         TIMER_PROFILE_ROUTINE(&stack);
  503.     }
  504.     } else {
  505.     /*
  506.      * Save pc for user profiling.
  507.      */
  508.     assert((stack.excStack.statusReg & MACH_SR_SUPSTATE) == 0);
  509.     Proc_GetCurrentProc()->Prof_PC = stack.excStack.pc;
  510.     }
  511.     /*
  512.      * Cut the call-back frequency in half.
  513.      */
  514.     callbackTimerToggle = !callbackTimerToggle;
  515.     if (callbackTimerToggle) {
  516.     TIMER_CALLBACK_ROUTINE(interval, time);
  517.     }
  518.     return 0;
  519. }
  520.  
  521.  
  522. /*
  523.  *----------------------------------------------------------------------
  524.  *
  525.  * Timer_CounterInit --
  526.  *
  527.  *    Initializes the chip's free-running counters.
  528.  *    The STOP command stops the counter and the RUN command turns
  529.  *    it back on.
  530.  *
  531.  * Results:
  532.  *    None.
  533.  *
  534.  * Side effects:
  535.  *    None.
  536.  *
  537.  *----------------------------------------------------------------------
  538.  */
  539.  
  540. void
  541. Timer_CounterInit()
  542. {
  543.     timerRegsPtr->commandReg = IntersilCommand(STOP, timerIntrState);
  544.     timerRegsPtr->counter = initialCounter;
  545.     timerRegsPtr->commandReg = IntersilCommand(RUN, timerIntrState);
  546. }
  547.  
  548.  
  549. /*
  550.  *----------------------------------------------------------------------
  551.  *
  552.  * Timer_CounterRead --
  553.  *
  554.  *    Read the contents of the counters. Interrupts are assumed
  555.  *    to be disabled to assure that the counters are read atomically.
  556.  *
  557.  * Results:
  558.  *    None.
  559.  *
  560.  * Side effects:
  561.  *    None.
  562.  *
  563.  *----------------------------------------------------------------------
  564.  */
  565.  
  566. void
  567. Timer_GetCurrentTicks(timePtr)
  568.     Timer_Ticks    *timePtr;    /* Time from the counters. */
  569. {
  570.     IntersilCounters    counter;
  571.  
  572.     /*
  573.      * Read the chip's counters.
  574.      */
  575.  
  576.     counter = timerRegsPtr->counter;
  577.     CountersToTime(&counter, timePtr);
  578. }
  579.  
  580.  
  581. /*
  582.  *----------------------------------------------------------------------
  583.  *
  584.  * CountersToTime --
  585.  *
  586.  *    Converts the values in the Intersil free-running counters
  587.  *    to a time value.
  588.  *
  589.  * Results:
  590.  *    None.
  591.  *
  592.  * Side effects:
  593.  *    None.
  594.  *
  595.  *----------------------------------------------------------------------
  596.  */
  597.  
  598. static void
  599. CountersToTime(counterPtr, timePtr)
  600.     register IntersilCounters    *counterPtr;
  601.     register Time        *timePtr;
  602. {
  603.     register int seconds = 0;
  604.     register int *accumPtr;
  605.  
  606.     if (counterPtr->year != 0) {
  607.     seconds += (counterPtr->year * SECS_PER_YEAR) +
  608.            (((counterPtr->year + 3) / 4) * SECS_PER_DAY);
  609.     }
  610.  
  611.     /*
  612.      * Is it a leap year?
  613.      */
  614.     if ((counterPtr->year % 4) == 0) {
  615.     accumPtr = accumSecsPerMonthLeap;
  616.     } else {
  617.     accumPtr = accumSecsPerMonth;
  618.     }
  619.  
  620.     timePtr->seconds = seconds +
  621.         accumPtr[counterPtr->month] +
  622.         ((counterPtr->day - 1) * SECS_PER_DAY) +
  623.         (counterPtr->hours * SECS_PER_HOUR) +
  624.         (counterPtr->minutes * 60) +
  625.         counterPtr->seconds;
  626.     timePtr->microseconds = (counterPtr->hundredths * HUNDREDTH_SECOND);
  627. }
  628.  
  629.  
  630.  
  631. /*  @#@#@#@#@#@#@#@#@#@#@    DEBUGGING CODE    @#@#@#@#@#@#@#@#@#@#@  */
  632.  
  633. /*
  634.  *----------------------------------------------------------------------
  635.  *
  636.  * Timer_TimerGetInfo --
  637.  *
  638.  *    Debugging routine to print the contents of the free-running
  639.  *    counters.
  640.  *
  641.  * Results:
  642.  *    None.
  643.  *
  644.  * Side effects:
  645.  *    None.
  646.  *
  647.  *----------------------------------------------------------------------
  648.  */
  649.  
  650. /*ARGSUSED*/
  651. void
  652. Timer_TimerGetInfo(data)
  653.     ClientData    data;        /* Ignored. */
  654. {
  655.     IntersilCounters  counter;
  656.     Time    time;
  657.  
  658.     if ((int) data == 1) {
  659.     DISABLE_INTR();
  660.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_ENABLE);
  661.     ENABLE_INTR();
  662.     return;
  663.     }
  664.  
  665.     DISABLE_INTR();
  666.     counter = timerRegsPtr->counter;
  667.     ENABLE_INTR();
  668.  
  669.     printf("Hundredths    %d\n", counter.hundredths);
  670.     printf("Seconds        %d\n", counter.seconds);
  671.     printf("Minutes        %d\n", counter.minutes);
  672.     printf("Hours        %d\n", counter.hours);
  673.     printf("Day        %d\n", counter.day);
  674.     printf("Month        %d\n", counter.month);
  675.     printf("Year        %d\n", counter.year);
  676.     printf("Day of Week    %d\n", counter.dayOfWeek);
  677.  
  678.     CountersToTime(&counter, &time);
  679.     printf("Time:    %d.%06u\n", time.seconds, time.microseconds);
  680. }
  681.  
  682. #ifdef NOT_USED
  683.  
  684. static void
  685. TimeToCounters(time, counterPtr)
  686.     Time    time;
  687.     register IntersilCounters    *counterPtr;
  688. {
  689.     int    *accumPtr;
  690.     register int seconds;
  691.  
  692. #define SECS_SINCE_1970_FOR(year) \
  693. (((year - 1970) * SECS_PER_YEAR) + ((((year - 1970) + 3) / 4) * SECS_PER_DAY))
  694.  
  695.     seconds = time.seconds - SECS_SINCE_1970_FOR(1984);
  696.  
  697.     if (seconds < 0) {
  698.     printf( "Tried to set time before 1984\n");
  699.     return;
  700.     }
  701.  
  702.     counterPtr->year = seconds / SECS_PER_YEAR;
  703.     seconds %= SECS_PER_YEAR;
  704.     seconds -= ((counterPtr->year + 3) / 4) * SECS_PER_DAY;
  705.  
  706.     if ((counterPtr->year % 4) == 0) {
  707.     accumPtr = accumSecsPerMonthLeap;
  708.     } else {
  709.     accumPtr = accumSecsPerMonth;
  710.     }
  711.  
  712.     for (month = 1; month < 13; month++) {
  713.     if (seconds < accumPtr[month]) {
  714.         seconds -= accumPtr[month];
  715.         counterPtr->month = month;
  716.         break;
  717.     }
  718.     }
  719.     counterPtr->day = (seconds / SECS_PER_DAY) + 1;
  720.     seconds %= SECS_PER_DAY;
  721.     counterPtr->hours = seconds / SECS_PER_HOUR;
  722.     seconds %= SECS_PER_HOUR;
  723.     counterPtr->minutes = seconds / 60;
  724.     counterPtr->seconds = seconds % 60;
  725.  
  726.     counterPtr->tenths = time.microseconds / TENTH_SECOND;
  727.     counterPtr->hundredths = 
  728.         (time.microseconds % TENTH_SECOND) / HUNDREDTH_SECOND;
  729. }
  730. #endif /* NOT_USED */
  731.  
  732.  
  733. /*
  734.  *----------------------------------------------------------------------
  735.  *
  736.  * TimerHardwareUniversalTimeInit --
  737.  *
  738.  *     Not implemented yet.
  739.  *
  740.  * Results:
  741.  *    None.
  742.  *
  743.  * Side effects:
  744.  *    None.
  745.  *
  746.  *----------------------------------------------------------------------
  747.  */
  748.  
  749. /*ARGSUSED*/
  750. void
  751. TimerHardwareUniversalTimeInit(timePtr, localOffsetPtr, DSTPtr)
  752.     Time *timePtr;        /* Buffer to hold universal time. */
  753.     int  *localOffsetPtr;    /* Buffer to hold local offset. */
  754.     Boolean *DSTPtr;        /* Buffer to hold DST allowed flag. */
  755. {
  756. }
  757.  
  758. /*
  759.  *----------------------------------------------------------------------
  760.  *
  761.  * TimerSetHardwareUniversalTime --
  762.  *
  763.  *    Not implemented yet.
  764.  *
  765.  * Results:
  766.  *    None.
  767.  *
  768.  * Side effects:
  769.  *    None.
  770.  *
  771.  *----------------------------------------------------------------------
  772.  */
  773.  
  774. /*ARGSUSED*/
  775. void
  776. TimerSetHardwareUniversalTime(timePtr, localOffset, DST)
  777.     Time *timePtr;        /* universal time. */
  778.     int  localOffset;        /* local offset. */
  779.     Boolean DST;        /* DST allowed flag. */
  780. {
  781. }
  782.